package modbus

//modbus数据流处理
import (
	"go-nest/tool"
	"sync"
)

type HandleFunc func(m *ModBus)
type ByteStream struct {
	sync.Mutex        //继承锁
	heads      []byte //包头
	buffer     []byte //缓存
}

func NewByteStream() *ByteStream {
	o := new(ByteStream)
	return o
}

//设置头
func (this *ByteStream) SetHead(hd []byte) {
	this.heads = hd
}

//消息处理
func (this *ByteStream) HandleMessage(data []byte, succCall HandleFunc) {
	this.Lock()
	defer this.Unlock()
	this.buffer = append(this.buffer, data...)
	for {
		mb, lost, again := this.parseBuf(this.buffer)
		this.buffer = lost
		if mb != nil {
			succCall(mb)
		}
		if again {
			continue
		}
		break
	}
}

//解析数据，并实施crc校验
//3 4 16 1 63 1 180 1 64 1 97 1 50 1 68 1 131 1 141 108 5
func (this *ByteStream) parseBuf(data []byte) (succ *ModBus, lost []byte, again bool) {
	headLen := 2 //包头长度
	longLen := 1 //数据长度长度
	stopLen := 2 //结束位数据长度
	l := len(data)
	if l < 5 { //长度不够(等待)
		//fmt.Println("长度不够")
		return nil, data, false
	}
	if string(this.heads) != string(data[:2]) { //包头不对(再来)
		return nil, data[1:], true
	}
	dataLen := int(data[2])                         //数据内容长度
	pkgLen := headLen + longLen + dataLen + stopLen //包长度
	if l < pkgLen {                                 //包长还是不够(等待)
		//fmt.Println("包长还是不够")
		return nil, data, false
	}
	start := 0                                        //数据的开始位置
	stop := pkgLen - stopLen                          //数据的结束位置
	stopData := data[stop:pkgLen]                     //结束位
	if string(CRC(data[:stop])) != string(stopData) { //包尾不对(再来)
		//fmt.Println("包尾不对")
		return nil, data[1:], true
	}
	succ = this.decodeModbus(data[start:stop]) //成功数据
	lost = data[pkgLen:]                       //剩余数据
	if len(lost) > 0 {                         //数据还没有处理完(再来)
		again = true
	}
	return
}

//解析modbus,无crc
func (this *ByteStream) decodeModbus(data []byte) *ModBus {
	mb := new(ModBus)
	tool.ByteToNumber(data[:1], &mb.Addr)
	tool.ByteToNumber(data[1:2], &mb.Code)
	tool.ByteToNumber(data[2:3], &mb.Length)
	mb.Data = data[3:]
	mb.FullData = data
	return mb
}
